package binocle

import (
	"gddgame.cc/galaxy/asteroid/cluster"
	"gddgame.cc/galaxy/binocle/logic"
	"gddgame.cc/galaxy/binocle/module/notice"
	"gddgame.cc/galaxy/binocle/module/proxy"
	"gddgame.cc/galaxy/binocle/module/reload"
	"gddgame.cc/galaxy/binocle/module/report"
	"gddgame.cc/galaxy/binocle/module/schedule"
	"gddgame.cc/galaxy/utils"
	"gddgame.cc/galaxy/utils/def"

	"github.com/pkg/errors"
)

type CoreClient interface {
	AgentClient

	logic.Watcher
	report.CoreReporter
	reload.Reloader
	schedule.CoreScheduler
	notice.CoreNoticer
	proxy.DataCenter
}
type Core interface {
	Config(config Config) error
	Client() CoreClient
	Cluster() cluster.Engine
	Start() error
	Close() error
}

type core struct {
	agent    *agent
	dc       string
	dcConfig map[string]interface{}

	client CoreClient
	proxy  *proxy.CoreProxy

	inited bool
}
type coreClient struct {
	*agentClient

	*logic.WatcherInstance
	report.CoreReporter
	reload.Reloader
	schedule.CoreScheduler
	notice.CoreNoticer
	proxy.DataCenter
}

func NewCore(logger def.Logger, namespace string, group string, dc string, dcConfig map[string]interface{}, adaptFn AdaptHandler) *core {
	core := &core{
		agent:    NewAgent(logger.LoggerWrap("With", "core"), namespace, group, adaptFn),
		dc:       dc,
		dcConfig: dcConfig,
	}
	return core
}

func (core *core) Config(config Config) error {
	if core.inited {
		return errors.New("Bincole is running")
	}
	layer, adapt, err := core.agent.initNode(config)
	if err != nil {
		return err
	}
	if config.Meta == nil {
		config.Meta = make(map[string]string)
	}
	config.Meta["type"] = "service"
	config.Meta["role"] = "core"

	client, err := core.agent.initClient(config, layer, adapt)
	if err != nil {
		return err
	}
	watcher := logic.NewWatcher(config.Name, DefaultCore, &layer.Channel)
	watcher.SetStrategy(client.region)

	wan := ""
	var groups []string
	if dataCenter, ok := core.dcConfig[core.dc]; ok {
		info := dataCenter.(map[interface{}]interface{})
		wan = info["wan"].(string)
	}
	core.proxy = proxy.NewCore(core.dc, wan, watcher, client.System)
	if list, ok := core.dcConfig["list"]; ok {
		info := utils.ToStringSlice(list)
		for _, dc := range info {
			if dataCenter, ok := core.dcConfig[dc]; ok {
				info := dataCenter.(map[interface{}]interface{})
				if w, o := info["wan"]; o {
					wan = utils.ToString(w)
				} else {
					wan = ""
				}
				if g, o := info["groups"]; o {
					groups = utils.ToStringSlice(g)
				} else {
					groups = nil
				}
				core.proxy.Register(dc, wan, groups)
			}
		}
	}
	// 注册代理路由
	layer.BindRouter(core.proxy)

	core.client = &coreClient{
		agentClient:     client,
		WatcherInstance: watcher,
		CoreReporter:    report.NewCore(watcher, client.System),
		Reloader:        reload.NewCore(watcher, client.System),
		CoreScheduler:   schedule.NewCore(watcher),
		CoreNoticer:     notice.NewCore(watcher),
		DataCenter:      core.proxy.Manager(),
	}
	core.inited = true
	return nil
}

func (core *core) Client() CoreClient {
	return core.client
}

func (core *core) Cluster() cluster.Engine {
	return core.agent.cluster
}

func (core *core) Start() error {
	return core.agent.Start()
}

func (core *core) Close() error {
	if err := core.agent.Close(); err != nil {
		return err
	}
	return nil
}
